Release 10.1A: OpenEdge Development:
Progress 4GL Handbook
Extending the test window to use a buffer handle
In this section, you’ll extend the
h-CustOrderWin8.wprocedure beyond the changes you already made in this chapter to illustrate the use and the value of some of the buffer handle attributes and methods. To preserve the first set of changes separately, this variant of the procedure is saved ash-CustOrderWin9.w. You’ll add buttons to the window to reposition within the current query to a particular record, and also to use a dynamicFINDmethod to locate and display a single record without using the query at all.
![]()
To extend the sample window to use a buffer handle:
- Define another variable in the Definitions section to record which of several new buttons the user selected:
This variable keeps track of whether the user chose the Filter button or one of the new buttons labeled Reposition and Find that you’ll define next.
- Drop two new buttons onto the window beneath the Filter button. Call them btnRepos and btnFind and give them the labels Reposition and Find, respectively.
- Extend the existing
CHOOSEtrigger onbtnFilterto fire for the other buttons, just as you did for the Customer field’sLEAVEtrigger before:
![]()
- At the end of the trigger, add a line to save off which button was chosen:
- Go into the
LEAVEtrigger for CustNum (which of course applies to all the Customer fields). Define a variable to hold the buffer handle:
- After the statement that assigns the query handle and
PREPARE-STRING, start a block based on the value of the newcBtnChoicevariable. Execute the existing code only if the button chosen was Filter:
- End the
DOblock for the Filter choice and start anELSEblock for the Reposition choice. Save off the Customer buffer handle and execute aFIND-FIRSTmethod on it that once again uses theBEGINSkeyword forCHARACTERfields and the = comparison otherwise. Execute theFIND-FIRSTmethod asNO-ERRORin case there’s no such record:
- Use the
AVAILABLEattribute to check whether there was a matching record. If there was, use theREPOSITION-TO-ROWIDmethod on the query handle to position the query to that record using its RowID. Do this operationNO-ERROR. ApplyCHOOSEto the Next button to position onto the record itself, display it, and retrieve its Orders:
There are a few things worth examining here. First, remember that because you are using the
FIND-FIRSTmethod, and notFIND-UNIQUE, Progress retrieves a record into the buffer even if there’s more than one match. TheAMBIGUOUSattribute is never true in this case.Second, you might be a little confused about why you have to reposition the query to the record you just retrieved in the buffer. Isn’t it already there for you to see? Yes, it is. If you leave out the
REPOSITIONmethod on the query and just display the contents of the buffer, you see the recordFIND-FIRSTretrieved. But if you then click the Next button, you don’t see the next record following the oneFIND-FIRSTretrieved. You just see the next record in the query as it was before you ever did theFIND-FIRST. The reason for this is that theFIND-FIRSTmethod on the buffer handle is effectively reusing the buffer for a purpose completely separate from the query. There is no connection between theFINDmethod and the records in the query. That’s really the purpose of theFINDmethods, that they allow you to fetch a specific record without using a query at all. To use theFINDmethod to reposition the query, you need code similar to what you just wrote, which uses the RowId to reposition the query to the same record.Also, remember why the
NEXToperation is required. If you use one of theFINDmethods on a buffer, the record you want is placed in the buffer, and you can use it immediately. But if you use one of the query handle’sREPOSITIONmethods, the query cursor is effectively placed immediately before the record you are repositioning to, so you need theGET NEXTstatement to actually bring that record into the buffer.And finally, consider the
NO-ERRORqualifier on theFIND-FIRSTmethod. It’s entirely possible that the user might click the Filter button and filter the query before clicking the Reposition button, and then enter a value to reposition to that’s in the Customer table (and therefore found by theFIND-FIRSTmethod on the buffer) but not in the query’s result set as it has been filtered. For example, the user could filter on Customer Names beginning with A, and then reposition to the first Customer Name beginning with B. Progress successfully retrieves the first Customer Name starting with B from the database, but then theREPOSITIONmethod on the query fails because that record is not in the query’s result list. This is important to keep in mind as you use these objects and their methods.- Check whether there’s a record available and display a message if there is not:
In such a case, a record might not be available either because there was no matching record in the database or because that record was not in the query.
- Define a block of code to support the Find button. Because the Find button is identifying a single record, the code uses the
FIND-UNIQUEbuffer method:
Because you’re trying to find just one matching record, the comparison operator in the
WHEREclause is simply "=".As before, you need to invoke the method with the
NO-ERRORqualifier, in case the selection either doesn’t yield a record or yields more than one matching record. Next, you need to check for those conditions.- Add code to check the
AMBIGUOUSandAVAILABLEattributes to make sure you got exactly one match:
- Write the code to handle the successful case.
- Close the Customer query.
- Disable the navigation buttons and the Reposition button because they don’t apply if you’ve just got one record.
- Display the record that the
FIND-UNIQUEmethod retrieved.- Reopen the Order Browse:
Why close the query? Because you’re not using it. You found a record using the same buffer the query uses, but that record is not in any way related to the query.
Why disable the buttons? Because they expect to be able to navigate through the query or reposition within it. You’d get an error if you allowed the user to choose them.
You can copy the
DISPLAYstatement and the{&OPEN-BROWSERS-IN-QUERY-CustQuery}preprocessor from any of the navigation triggers. As you did in an earlier exercise, you could clean this up by factoring out the repeated code into an include file or internal procedure.Don’t forget to end all your blocks properly, with a comment on each
ENDstatement to help you verify the block structure as things get more complex.Because the Find button disables the navigation and Reposition buttons, the block of code in the same trigger for the Filter button needs to re-enable them.
- Add this
ENABLEstatement to that block, after it reopens the query:
- Try out the procedure with various combinations of actions. When you click the Find button, for instance, it should enable the fields, accept input, and then disable the fields along with the navigation and Reposition buttons and display the one matching record:
![]()
Using various other Filter, Find, and Reposition requests, you can test the various error conditions that you wrote code to handle.
|
Copyright © 2005 Progress Software Corporation www.progress.com Voice: (781) 280-4000 Fax: (781) 280-4095 |